quantwave_core/features/
cyber_cycle.rs1use crate::indicators::cyber_cycle::CyberCycle;
10use crate::traits::Next;
11
12#[derive(Debug, Clone, Copy, PartialEq)]
14pub struct CyberCycleFeatures {
15 pub cycle: f64,
16 pub trigger: f64,
17 pub cycle_momentum: f64,
19 pub trigger_signal: f64,
21}
22
23#[derive(Debug, Clone)]
24pub struct CyberCycleFeatureExtractor {
25 inner: CyberCycle,
26 prev_cycle: f64,
27}
28
29impl CyberCycleFeatureExtractor {
30 pub fn new(length: usize) -> Self {
31 Self {
32 inner: CyberCycle::new(length),
33 prev_cycle: 0.0,
34 }
35 }
36}
37
38impl Next<f64> for CyberCycleFeatureExtractor {
39 type Output = CyberCycleFeatures;
40
41 fn next(&mut self, input: f64) -> Self::Output {
42 let (cycle, trigger) = self.inner.next(input);
43
44 let momentum = if self.prev_cycle == 0.0 { 0.0 } else { cycle - self.prev_cycle };
45 let trigger_signal = (cycle - trigger).signum();
46
47 self.prev_cycle = cycle;
48
49 CyberCycleFeatures {
50 cycle,
51 trigger,
52 cycle_momentum: momentum,
53 trigger_signal,
54 }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use approx::assert_relative_eq;
62
63 #[test]
64 fn test_cyber_cycle_features_basic() {
65 let mut extractor = CyberCycleFeatureExtractor::new(14);
66
67 for i in 0..50 {
69 let val = 100.0 + 5.0 * (i as f64 * 0.3).sin();
70 let f = extractor.next(val);
71 if !f.cycle.is_nan() {
72 assert!(f.cycle.abs() < 20.0); }
74 }
75 }
76}