quantwave_core/features/
hurst.rs1use crate::indicators::hurst::HurstExponent;
14use crate::traits::Next;
15
16#[derive(Debug, Clone, Copy, PartialEq)]
18pub struct HurstFeatures {
19 pub persistence: f64,
20 pub regime_label: Option<i8>,
23}
24
25impl HurstFeatures {
26 pub fn new(persistence: f64, regime_label: Option<i8>) -> Self {
27 Self { persistence, regime_label }
28 }
29}
30
31#[derive(Debug, Clone)]
33pub struct HurstFeatureExtractor {
34 inner: HurstExponent,
35 mean_reverting_threshold: f64,
37 trending_threshold: f64,
38}
39
40impl HurstFeatureExtractor {
41 pub fn new(period: usize) -> Self {
42 Self {
43 inner: HurstExponent::new(period),
44 mean_reverting_threshold: 0.45,
45 trending_threshold: 0.55,
46 }
47 }
48
49 pub fn with_thresholds(mut self, mean_rev: f64, trending: f64) -> Self {
50 self.mean_reverting_threshold = mean_rev;
51 self.trending_threshold = trending;
52 self
53 }
54}
55
56impl Next<f64> for HurstFeatureExtractor {
57 type Output = HurstFeatures;
58
59 fn next(&mut self, input: f64) -> Self::Output {
60 let persistence = self.inner.next(input);
61
62 let regime_label = if persistence.is_nan() {
63 None
64 } else if persistence < self.mean_reverting_threshold {
65 Some(-1)
66 } else if persistence > self.trending_threshold {
67 Some(1)
68 } else {
69 Some(0)
70 };
71
72 HurstFeatures::new(persistence, regime_label)
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use approx::assert_relative_eq;
80
81 #[test]
82 fn test_hurst_feature_basic() {
83 let mut extractor = HurstFeatureExtractor::new(20);
84
85 for i in 0..30 {
87 let val = 100.0 + (i as f64) * 0.5;
88 let f = extractor.next(val);
89 if !f.persistence.is_nan() {
90 assert!(f.persistence > 0.5, "Expected trending persistence, got {}", f.persistence);
91 }
92 }
93 }
94
95 #[test]
96 fn test_hurst_feature_regime_labels() {
97 let mut extractor = HurstFeatureExtractor::new(10)
98 .with_thresholds(0.4, 0.6);
99
100 let f = extractor.next(100.0);
103 if !f.persistence.is_nan() {
105 assert!(f.regime_label.is_some());
106 }
107 }
108}